package tp.badugi.client;

import java.awt.Color;
import java.awt.Font;
import java.awt.Point;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.WindowAdapter;
import java.awt.event.WindowEvent;
import java.io.IOException;
import java.util.Arrays;

import javax.swing.BorderFactory;
import javax.swing.JLabel;
import javax.swing.JOptionPane;
import javax.swing.border.EmptyBorder;

import tp.badugi.client.exceptions.TableNotCreatedClientException;
import tp.badugi.client.exceptions.TableNotJoinedClientException;
import tp.badugi.client.guiViews.ActionView;
import tp.badugi.client.guiViews.CardChangeView;
import tp.badugi.client.guiViews.ConnectionView;
import tp.badugi.client.guiViews.GameView;
import tp.badugi.client.guiViews.GetActionAmoutView;
import tp.badugi.client.guiViews.GetNicknameView;
import tp.badugi.client.guiViews.ServerView;
import tp.badugi.client.guiViews.WinnerView;
import tp.badugi.net.GameStatus;
import tp.badugi.net.iRequestListener;
import tp.badugi.net.exceptions.IllegalCharactersException;
import tp.badugi.net.exceptions.IllegalParameterValueException;
import tp.badugi.net.exceptions.NameTakenException;
import tp.badugi.net.exceptions.NoSuchTableException;
import tp.badugi.net.exceptions.RequestTimedOutException;
import tp.badugi.net.exceptions.ServerCouldNotCompleteRequestException;
import tp.badugi.net.exceptions.TableFullException;

public class GuiClient implements iClientFrontAdapter, ActionListener{
	
	private iClientBridgeAdapter clientBridge;
	
	private ConnectionView connectionView;
	private ServerView serverView;
	private GameView gameView;
	private ActionView actionView;
	private CardChangeView cardChangeView;
	private WinnerView winnerView;
	private GetNicknameView getNicknameView;
	private GetActionAmoutView getActionAmountView;
	
	private JLabel validationMessager = new JLabel(); 
	
	public ImageProvider imageProvider;
	
	public String title = "baDOOGIE";
	public final Font clientFont = new Font("Trebuchet MS", Font.BOLD, 14);
	public final Point windowBoundPoint = new Point(200,200);
	
	public WindowAdapter windowAdapter = new WindowAdapter(){
		public void windowClosing(WindowEvent e) {
			disconnectFromGame();
		}
	};
	
	private String chosenAction = "";
	private boolean cardsToExchangeIndex[] = {false, false, false, false};
	
	private GuiClient(){
		this.clientBridge = new ClientBridgeAdapter(this);
		
		imageProvider = new ImageProvider();
		
		this.connectionView = new ConnectionView(this);
	}
	

	
	// -- Methods
	
	@Override
	public void writeConsoleMessage(String consoleMessage) {
		this.gameView.gameConsoleTextArea.append(consoleMessage + "\n");
		this.gameView.gameConsoleTextArea.setCaretPosition(
				this.gameView.gameConsoleTextArea.getDocument().getLength());
	}

	@Override
	public void writeErrorMessage(String errorMessage) {
		JOptionPane.showConfirmDialog
			(this.connectionView,
			errorMessage,
			"Error",
			JOptionPane.DEFAULT_OPTION,
			JOptionPane.ERROR_MESSAGE);
	}

	@Override
	public void writeConnectionMessage(String connectionMessage) {
		JOptionPane.showConfirmDialog
			(this.connectionView,
			connectionMessage,
			"Information",
			JOptionPane.DEFAULT_OPTION,
			JOptionPane.INFORMATION_MESSAGE);
	}

	@Override
	public void writeValidationMessage(String validationMessage) {
		this.validationMessager.setText(validationMessage);
	}

	@Override
	public void updateGameData(GameStatus gameStatus, String serverIpAddress, int serverPortNumber) {
		this.gameView.refreshView(gameStatus, serverIpAddress, serverPortNumber);
	}

	@Override
	public void showConnectionView() {
		
		this.resetViews();
		
		this.connectionView.setVisible(true);
	}  

	@Override
	public void showServerView(String serverIpAddress, int serverPortNumber,
			String[] serverList) {
		if(this.serverView == null){
			this.serverView = new ServerView(this, serverIpAddress, serverPortNumber, serverList);
		}
		else{
			this.serverView.refreshView(serverIpAddress, serverPortNumber, serverList);
		}
				
		this.resetViews();
		
		this.serverView.setVisible(true);
		
	}

	@Override
	public void showGameView(GameStatus gameStatus, String serverIpAdress,
			int serverPortNumber) {
		
		if(this.gameView == null){
			this.gameView = new GameView(this, gameStatus, serverIpAdress, serverPortNumber);
		}
		
		this.resetViews();
		
		this.gameView.setVisible(true);
	}

	@Override
	public void showActionView(String[] possibleActions, int timeout,
			long currentBetDifference, long minimalRaise) {
		
		if(this.actionView == null){
			this.actionView = new ActionView(this, possibleActions, timeout, currentBetDifference, minimalRaise);
		}
		
		this.actionView.refreshView(possibleActions);
		
		this.actionView.setVisible(true);
	}

	@Override
	public void showCardChangeView(String[] cards, int timeout) {
		
		if(this.cardChangeView == null){
			this.cardChangeView = new CardChangeView(this, cards, timeout);
		}
		
		this.cardChangeView.refreshView(cards);
		
		this.cardChangeView.setVisible(true);
	}

	@Override
	public void showRoundWinnerView(String[][] revealedPlayersCards,
			String[] playerNames, long[] chipsAddedFromPot,
			int[] winnersIndexes) {
		
		if(this.winnerView == null){
			this.winnerView = new WinnerView(this, revealedPlayersCards, playerNames, chipsAddedFromPot, winnersIndexes);
		}
		else{
			this.winnerView.createNewView(revealedPlayersCards, playerNames, chipsAddedFromPot, winnersIndexes);
		}
		
		this.winnerView.setVisible(true);
	}

	@Override
	public void actionPerformed(ActionEvent ae) {
		
		if(this.connectionView != null &&
				ae.getSource() == this.connectionView.connectionConnectToServerButton){
			this.connect(this.connectionView.connectionServerIpAddressField.getText()
					, this.connectionView.connectionServerPortNumber.getText());;
		}
		
		else if(this.serverView != null &&
				ae.getSource() == this.serverView.serverJoinTable){
			this.showGetNicknameView();
		}
		
		else if(this.getNicknameView != null &&
				ae.getSource() == this.getNicknameView.nicknameJoin){
			this.joinTable(this.serverView.serverList.getSelectedValue(), this.getNicknameView.nicknameTextField.getText());
		}
		
		else if(this.serverView != null &&
				ae.getSource() == this.serverView.serverRefresh){
			this.refreshServerView();
		}
		
		else if(this.serverView != null &&
				ae.getSource() == this.serverView.serverDisconnect){
			this.disconnectFromServer();
		}
		
		else if(this.serverView != null &&
				ae.getSource() == this.serverView.serverCreate){
			
			this.createTable(	this.serverView.serverTableNameTextField.getText(),
								this.serverView.serverPlayerNameTextField.getText(),
								this.serverView.serverTableSizeTextField.getText(),
								this.serverView.serverStartingChipsTextField.getText(),
								this.serverView.serverSmallBlind.getText(),
								this.serverView.serverBigBlind.getText()	);
		}
		
		else if(this.gameView != null &&
				ae.getSource() == this.gameView.gameLeaveTable){
			this.leaveTable();
		}
		
		else if(this.gameView != null &&
				ae.getSource() == this.gameView.gameDisconnect){
			this.disconnectFromServer();
		}
		
		else if(this.actionView != null
				&& ae.getSource() == this.actionView.actionTimer){
			if(this.actionView.actionTimeoutCount > 0){
				this.actionView.actionTimeoutCount --;
				this.actionView.actionTimerLabel.setText(
									String.valueOf(this.actionView.actionTimeoutCount));
			}
			else{
				this.actionView.actionTimer.stop();
				if (this.getActionAmountView != null){
					this.getActionAmountView.setVisible(false);
				}
				this.actionView.setVisible(false);
			}
		}
		
		else if(this.actionView != null && ae.getSource() == this.actionView.actionCheckButton){
			this.actionChosen(iRequestListener.ACTION_CHECK);
		}

		else if(this.actionView != null && ae.getSource() == this.actionView.actionCallButton){
			this.actionChosen(iRequestListener.ACTION_CALL);
		}
		
		else if(this.actionView != null && ae.getSource() == this.actionView.actionBetButton){
			this.actionChosen(iRequestListener.ACTION_BET);
		}
		
		else if(this.actionView != null && ae.getSource() == this.actionView.actionRaiseButton){
			this.actionChosen(iRequestListener.ACTION_RAISE);
		}
		
		else if(this.actionView != null && ae.getSource() == this.actionView.actionAllInButton){
			this.actionChosen(iRequestListener.ACTION_ALLIN);
		}
		
		else if(this.actionView != null && ae.getSource() == this.actionView.actionFoldButton){
			this.actionChosen(iRequestListener.ACTION_FOLD);
		}
		
		else if(this.getActionAmountView != null &&
				ae.getSource() == this.getActionAmountView.actionAmountButton){
			this.respondToActionReqest(this.chosenAction, this.getActionAmountView.actionAmountTextFiled.getText());
		}
		
		else if(this.cardChangeView != null
				&& ae.getSource() == this.cardChangeView.cardTimer)
		{
			if (this.cardChangeView.cardTimeoutCount > 0)
			{
				this.cardChangeView.cardTimeoutCount--;
				this.cardChangeView.cardTimerLabel.setText(
									String.valueOf(this.cardChangeView.cardTimeoutCount));
			}
			else
			{
				this.cardChangeView.cardTimer.stop();
				this.cardChangeView.setVisible(false);
			}
		}
		
		else if(this.cardChangeView != null  && ae.getSource() == this.cardChangeView.cardButton[0] ){
			this.changeCardButtonColorAndState(0);

		}
		
		else if(this.cardChangeView != null  && ae.getSource() == this.cardChangeView.cardButton[1] )
		{
			this.changeCardButtonColorAndState(1);

		}
		
		else if(this.cardChangeView != null  && ae.getSource() == this.cardChangeView.cardButton[2] ){
			this.changeCardButtonColorAndState(2);

		}
		
		else if(this.cardChangeView != null  && ae.getSource() == this.cardChangeView.cardButton[3] ){
			this.changeCardButtonColorAndState(3);

		}
		
		else if(this.cardChangeView != null &&
				ae.getSource() == this.cardChangeView.cardExchangeButton){
			System.out.println(Arrays.toString(this.cardsToExchangeIndex));
			this.respondToCardRequest(this.cardsToExchangeIndex, this.clientBridge.getGameStatus().myCards);
		}
		
		else if(this.cardChangeView != null &&
				ae.getSource() == this.cardChangeView.cardCancelButton){
			Arrays.fill(this.cardsToExchangeIndex, false);
			System.out.println(Arrays.toString(this.cardsToExchangeIndex));
			this.respondToCardRequest(this.cardsToExchangeIndex, this.clientBridge.getGameStatus().myCards);
		}
		
		else if(this.winnerView != null &&
				ae.getSource() == this.winnerView.winnerCloseViewButton){
			this.winnerView.setVisible(false);
		}
		
		else if (this.winnerView != null &&
				ae.getSource() == this.winnerView.winnerTimer){
			this.winnerView.winnerTimer.stop();
			this.winnerView.setVisible(false);
		}
	}
	
	// --private
	private void showGetNicknameView(){
		
		if( this.getNicknameView == null){
			this.getNicknameView = new GetNicknameView(this);
		}
		
		this.getNicknameView.setVisible(true);
	}
	
	private void showGetActionAmount(){
		
		if( this.getActionAmountView == null){
			this.getActionAmountView = new GetActionAmoutView(this);
		}
		
		this.getActionAmountView.refreshView();
		this.getActionAmountView.setVisible(true);

	}
	
	private void connect(String serverIpAdderss, String serverPortNumber){		
		try{
			int port = Integer.parseInt(serverPortNumber);
			this.clientBridge.connect(serverIpAdderss, port);
		}
		catch(NumberFormatException ex){
			this.writeValidationMessage("Type valid port number");
		}
		catch(IOException | ServerCouldNotCompleteRequestException | RequestTimedOutException ex){
			this.writeValidationMessage(ex.getMessage());
		}	
	}

	private void joinTable(String tableName, String nickname){

		try{
			this.getNicknameView.setVisible(false);
			
			this.clientBridge.joinTable(tableName, nickname);
		}
		catch(TableFullException | IllegalArgumentException | IllegalCharactersException |
				ServerCouldNotCompleteRequestException | NameTakenException |
				NoSuchTableException | RequestTimedOutException |
				TableNotJoinedClientException ex){
			this.writeErrorMessage(ex.getMessage());
		}
	}
	
	private void refreshServerView(){

		try{
			this.clientBridge.refreshTableList();
		}
		catch(ServerCouldNotCompleteRequestException | RequestTimedOutException ex){
			this.writeErrorMessage(ex.getMessage());
		}
	}
	
	private void disconnectFromServer(){

		try{
			this.clientBridge.disconnectFromServer();
		}
		catch(IOException ex){
			this.writeErrorMessage(ex.getMessage());
		}
	}
	
	private void createTable(String tableName, String myNickname, String tableSize,
			String startingChips, String smallBlind, String bigBlind){
		int size = 0;
		int chips = 0;
		long sBlind = 0;
		long bBlind = 0;
		
		try{
			size = Integer.parseInt(tableSize);
		}
		catch(NumberFormatException ex){
			this.writeValidationMessage("Enter valid table size!");
		}
		
		try{
			chips = Integer.parseInt(startingChips);
		}
		catch(NumberFormatException ex){
			this.writeValidationMessage("Enter valid starting chips amount!");
		}
		try{
			sBlind = Long.parseLong(smallBlind);
		}
		catch(NumberFormatException ex){
			this.writeValidationMessage("Enter valid small blind size!");
		}
		try{
			bBlind = Long.parseLong(bigBlind);
			
			this.clientBridge.createTable(tableName, myNickname, size, chips, sBlind, bBlind);
		}
		catch(NumberFormatException ex){
			this.writeValidationMessage("Enter valid big blind size!");
		}
		catch(NameTakenException | IllegalCharactersException | IllegalParameterValueException |
				ServerCouldNotCompleteRequestException | RequestTimedOutException |
				TableNotCreatedClientException ex){
			this.writeErrorMessage(ex.getMessage());
		}
	}
	
	private void leaveTable(){
		try{
			this.clientBridge.leaveTable();
			this.gameView.gameConsoleTextArea.setText("");
		}
		catch(ServerCouldNotCompleteRequestException| RequestTimedOutException ex){
			this.writeErrorMessage(ex.getMessage());
		}
	}
	
	private void disconnectFromGame(){
		try{
			this.clientBridge.disconnectAndExitProgram();
		}
		catch(IOException ex){
			this.writeErrorMessage(ex.getMessage());
		}
	}
	
	private void actionChosen(String chosenAction){
		
		if (chosenAction == iRequestListener.ACTION_FOLD || 
			chosenAction == iRequestListener.ACTION_CHECK ||
			chosenAction == iRequestListener.ACTION_CALL )
		{
			this.respondToActionReqest(chosenAction, 0);
			this.actionView.setVisible(false);
		}
		else if (	chosenAction == iRequestListener.ACTION_BET ||
					chosenAction == iRequestListener.ACTION_RAISE)
		{
			this.chosenAction = chosenAction;
			this.showGetActionAmount();
		}
		
		else if (chosenAction == iRequestListener.ACTION_ALLIN)
		{
			this.respondToActionReqest(chosenAction, this.clientBridge.getGameStatus().myChipCount);
			this.actionView.setVisible(false);
		}
		
		else {
			this.writeErrorMessage("[UNDEFINED_ACTION]");
			this.actionView.setVisible(false);
		}
	}
	
	private void respondToActionReqest(String action, String chipAmount){
		try{
			long amount = Long.parseLong(chipAmount);
			
			this.clientBridge.makeAction(action, amount);
			this.actionView.setVisible(false);
			this.getActionAmountView.setVisible(false);
		}
		catch(NumberFormatException ex){
			this.writeValidationMessage("Enter valid data!");
		}
	}
	
	private void respondToActionReqest(String action, long chipAmount){
		this.clientBridge.makeAction(action, chipAmount);
		this.actionView.setVisible(false);
	}
	
	private void respondToCardRequest(boolean[] cardsToExchangeIndex, String[] myCards){
		String cardsToExchange[];
		int amount = 0;
		
		for(int i = 0; i < cardsToExchangeIndex.length; i++){
			if (cardsToExchangeIndex[i] == true){
				amount++;
			}
		}
		
		cardsToExchange = new String[amount];
		amount = 0;
		
		for(int i = 0; i < cardsToExchangeIndex.length; i++){
			if (cardsToExchangeIndex[i] == true){
				cardsToExchange[amount++] = myCards[i];
			}
		}
		
		System.out.println(Arrays.toString(cardsToExchange));
		
		this.clientBridge.changeCards(cardsToExchange);
		Arrays.fill(this.cardsToExchangeIndex, false);	
		this.cardChangeView.cardTimer.stop();
		this.cardChangeView.setVisible(false);
	}
	
	private void changeCardButtonColorAndState(int index){
		
		if(this.cardsToExchangeIndex[index] == false){
			this.cardsToExchangeIndex[index] = true;
			this.cardChangeView.cardButton[index].setBorder(BorderFactory.createMatteBorder(2, 2, 2, 2, Color.RED));
		}
		else{
			this.cardsToExchangeIndex[index] = false;
			this.cardChangeView.cardButton[index].setBorder(new EmptyBorder(0,0,0,0));
		}
		this.cardChangeView.cardButton[index].setOpaque(true);
	}
	
	private void resetViews(){
		
		if(this.connectionView != null){
			this.connectionView      .setVisible(false);
		}
		
		if(this.serverView != null){
			this.serverView          .setVisible(false);
		}
		
		if(this.gameView != null){
			this.gameView            .setVisible(false);
		}

		if(this.actionView   != null){
			this.actionView          .setVisible(false);
		}

		if(this.cardChangeView !=null){
			this.cardChangeView      .setVisible(false);
		}
		
		if(this.winnerView  !=null){
			this.winnerView          .setVisible(false);
		}
		if(this.getNicknameView !=null){
			this.getNicknameView     .setVisible(false);
		}
		
		if(this.getActionAmountView !=null){
			this.getActionAmountView .setVisible(false);
		}
		
	}
	
	public static void main(String[] args) {
		new GuiClient();
	}

}
